﻿using System.Reflection;
using Faml.Frontend;
using Faml.Operations;
using System.Collections.Generic;

namespace Faml.Optimization
{
    public class ExpandUnfoldsVisitor : IVisitor
    {
        private readonly int maxLength1d = 100 * 1024 * 1024 /* 100 Mb */ / sizeof(double);

        #region IVisitor Members

        public FamlExpression Visit(FamlExpression node)
        {
            if (node.NodeType != FamlExpressionType.FunctionCall)
                return node;

            FamlFunctionCallExpression fce = (FamlFunctionCallExpression)node;

            int resultRank = fce.Type.GetArrayRank();
            if (resultRank == 1)
            {
                int lenIndex = 0, dataIndex = 1;
                if (fce.Arguments[1].Type == typeof(int))
                {
                    lenIndex = 1; dataIndex = 0;
                }

                int length = GetValueFrom(fce.Arguments[lenIndex]);
                if (length > maxLength1d)
                {
                    System.Diagnostics.Debug.WriteLine(string.Format("Length of unfold is too large: {0}; skipping...", length));
                    return node;
                }

                FamlExpression[] items = new FamlExpression[length];

                FamlInlineArrayExpression array1d = new FamlInlineArrayExpression(items);
                return array1d;
            }

            return node;
        }

        #endregion

        private int GetValueFrom(FamlExpression famlExpression)
        {
            if (famlExpression.NodeType == FamlExpressionType.Constant)
            {
                return (int)((FamlConstant)famlExpression).Value;
            }

            FamlReferenceExpression famlRef = (FamlReferenceExpression)famlExpression;
            return (int)famlRef.ReferencedContainer.Value;
        }

    }
}
